"""
实验运行器 - 通过命令行界面引导用户手动完成实验
"""

import pickle
from collections.abc import Mapping
from datetime import datetime
from pathlib import Path
from typing import Any

from ax.api.client import Client
from ax.api.configs import ChoiceParameterConfig

from src.preexisting_trial import load_preexisting_trial


def config_client(
    client: Client,
    tail_temperature_range: list[int],
    motor_rpm: int,
    optimize_metric: str,
    preexisting_trials_dir: str | None,
):
    tail_temperature_parameters = []
    for i in range(1, 5):
        tail_temperature_parameters.append(
            ChoiceParameterConfig(
                name=f"t{i}",
                parameter_type="int",
                values=tail_temperature_range,
                is_ordered=True,
            )
        )

    client.configure_experiment(
        name=f"{optimize_metric}_{motor_rpm}rpm",
        parameters=tail_temperature_parameters,
        description="Optimize tail temperatures",
        owner="developer",
    )

    client.configure_optimization(
        objective=f"{optimize_metric}_{motor_rpm}rpm"
    )

    if preexisting_trials_dir is None:
        return client

    # 从数据目录加载已有的试验并将其加入当前优化器
    preexisting_trials = load_preexisting_trial(
        data_dir=preexisting_trials_dir,
        parameters=["t1", "t2", "t3", "t4"],
        optimization_metric=optimize_metric,
        motor_rpm=motor_rpm,
        force_reload=False,
    )

    for parameters, data in preexisting_trials:
        trial_index = client.attach_trial(parameters=parameters)
        client.complete_trial(trial_index=trial_index, raw_data=data)

    return client


def after_optimization(
    client: Client,
    results_dir: str,
    optimize_metric: str,
    motor_rpm: int,
):
    """
    在优化完成后进行结论分析并显示结果
    """
    # 获取性能最佳的配置
    client.get_best_parameterization()

    # 进行结论分析
    cards = client.compute_analyses(display=True)
    df = client.summarize()
    print(df)

    # 生成时间戳用于保存文件
    timestamp = datetime.now().strftime("%Y%m%d_%H-%M-%S")

    # 将dataframe保存为xlsx
    excel_path = (
        f"{results_dir}/{timestamp}_{optimize_metric}_{motor_rpm}rpm.xlsx"
    )
    df.to_excel(excel_path, index=False)

    # 保存分析图表为pickle文件
    cards_pickle_path = (
        f"{results_dir}/{timestamp}_{optimize_metric}_{motor_rpm}rpm_cards.pkl"
    )
    with open(cards_pickle_path, "wb") as f:
        pickle.dump(cards, f)

    # 保存优化快照
    client.save_to_json_file(
        f"{results_dir}/{timestamp}_{optimize_metric}_{motor_rpm}rpm.json"
    )


def run_experiment(
    iteration: int,
    parameters: Mapping[str, Any],
    motor_rpm: int,
    data_dir: str,
) -> Path | str:
    """
    引导用户手动完成实验并确认数据文件已生成

    Args:
        iteration: 当前实验迭代次数
        parameters: 实验参数字典，包含 x1, x2, x3, x4 (对应 T1, T2, T3, T4)

    Returns:
        生成的数据文件路径
    """
    # 提取温度参数
    t1 = parameters.get("t1", 0)
    t2 = parameters.get("t2", 0)
    t3 = parameters.get("t3", 0)
    t4 = parameters.get("t4", 0)

    # 建议的文件名格式
    suggested_filename = f"{t1}-{t2}-{t3}-{t4}-{motor_rpm}RPM.xlsx"

    # 显示实验指导信息
    print("\n" + "=" * 70)
    print(f"📍 第 {iteration + 1} 次实验")
    print("=" * 70)
    print("\n💡 建议测试参数:")
    print(f"   T1 = {t1}°C")
    print(f"   T2 = {t2}°C")
    print(f"   T3 = {t3}°C")
    print(f"   T4 = {t4}°C")
    print(f"   电机速度 = {motor_rpm} rpm")
    print("\n📁 建议数据文件名:")
    print(f"   {suggested_filename}")

    print(f"\n{'─' * 70}")
    print("📝 操作步骤:")
    print("  1. 在实验设备上设置上述温度参数")
    print("  2. 手动启动实验并采集数据")
    print(f"  3. 将数据文件保存到 {data_dir}/ 文件夹")
    print(f"  4. 确保文件名格式正确: {suggested_filename}")
    print(f"{'─' * 70}\n")

    # 等待用户确认实验完成
    while True:
        user_input = (
            input("实验状态? (Y=已完成并保存数据, S=跳过此实验, Q=退出): ")
            .strip()
            .upper()
        )

        if user_input == "Q":
            print("\n👋 用户选择退出")
            return "exit"

        elif user_input == "S":
            print("⏭️  跳过此次实验")
            return "skip"

        elif user_input == "Y":
            # 查找数据文件
            print("\n🔍 正在查找数据文件...")
            data_file = _find_data_file(t1, t2, t3, t4, motor_rpm)

            if data_file is None:
                print("  ✗ 未找到匹配的数据文件")
                print(f"    需要文件: {suggested_filename}")
                print("    查找路径: data/")
                retry = input("    重新查找? (Y/N): ").strip().upper()
                if retry == "Y":
                    continue
                else:
                    print("⏭️  跳过此次实验")
                    return "skip"

            print(f"  ✓ 找到数据文件: {data_file.name}")
            print(f"    完整路径: {data_file}")
            return data_file

        else:
            print("❓ 无效输入，请输入 Y (已完成)、S (跳过) 或 Q (退出)")


def _find_data_file(
    t1: int, t2: int, t3: int, t4: int, motor_speed: int
) -> Path | None:
    """
    在 data 文件夹中查找匹配的数据文件

    Args:
        t1, t2, t3, t4: 温度参数
        motor_speed: 电机速度 (rpm)

    Returns:
        找到的数据文件路径，未找到则返回 None
    """
    data_folder = Path("data")

    if not data_folder.exists():
        print(f"  ⚠️  数据文件夹不存在: {data_folder.absolute()}")
        return None

    # 文件名模式: T1-T2-T3-T4-{speed}RPM*.xlsx
    pattern = (
        f"{int(t1)}-{int(t2)}-{int(t3)}-{int(t4)}-{int(motor_speed)}RPM*.xlsx"
    )

    # 在当前目录下搜索匹配的文件
    matching_files = list(data_folder.glob(pattern))

    if not matching_files:
        return None

    # 如果找到多个文件，返回最新的（按修改时间）
    if len(matching_files) > 1:
        print(f"  ℹ️  找到 {len(matching_files)} 个匹配文件，将使用最新的一个")

    latest_file = max(matching_files, key=lambda p: p.stat().st_mtime)
    return latest_file
